module ysyx_050369_cache2axi (
	input               clk,    // Clock
	input               rst,  // Asynchronous reset active low
	input       [2:0]   size_t,
    input               axi_read ,
    input               unbrust,
    input               uncache,
    input       [31:0]  i_raddr,
    input       [31:0]  i_waddr,
    input       [7 :0]  wstrb_t,
    input				axi_write,
    input		[31:0]  dirty_addr,
    input		[127:0] i_wdata,

    output reg  [127:0] cache_wdata,
    output reg          wen ,
    output              wdone,
    output              rdone,



    input           	i_awready,              
    output          	o_awvalid ,
    output [31:0]   	o_awaddr ,
    output [3:0]    	o_awid ,
    output [7:0]    	o_awlen ,
    output [2:0]    	o_awsize ,
    output [1:0]    	o_awburst ,

    input           	i_wready,                
    output          	o_wvalid ,
    output [63:0]   	o_wdata ,
    output [7:0]    	o_wstrb ,
    output          	o_wlast ,
    
    output          	o_bready ,                
    input           	i_bvalid,
    input  [1:0]    	i_bresp,                 
    input  [3:0]    	i_bid,

    input           	i_arready,                
    output          	o_arvalid ,
    output [31:0]   	o_araddr ,
    output [3:0]    	o_arid ,
    output [7:0]    	o_arlen ,
    output [2:0]    	o_arsize ,
    output [1:0]    	o_arburst ,
    
    output          	o_rready ,                 
    input           	i_rvalid,                
    input  [1:0]    	i_rresp,
    input  [63:0]   	i_rdata,
    input           	i_rlast,
    input  [3:0]    	i_rid

);

reg   [31:0] araddr;
reg   [3:0]  arid;
reg   [7:0]  arlen;
reg          arvalid;
reg          rready;
reg  [2:0]   arsize;
reg  [1:0]   arburst;   
reg          awvalid ;
reg  [31:0]  awaddr;
reg  [3:0]   awid;
reg  [7:0]   awlen ;
reg  [2:0]   awsize ;
reg  [1:0]   awburst ;              
reg          wvalid ;
reg  [7:0]   wstrb ;
reg          bready ;   

reg [63:0]   wdata ;
reg [1:0]  wcnt,wcntm,wcnts;
reg [1:0]  rcnt,rcntm;
reg [2:0]  rstate,rnstate;
reg [2:0]  wstate,wnstate;
reg [1:0]  k;

parameter RIDLE=3'b0,AREAD=3'b001,READ=3'b010,FIN=3'b011,RDONE=3'b100,UBREAD=3'b101,UBREAD_WAIT=3'b111;
parameter WIDLE=3'h0,RCACHE=3'h1,WRITE=3'h2,WRES=3'h3,WDONE=3'h4,RDATA=3'h5;
always @(posedge clk ) begin 
	if(rst) rstate <= RIDLE; 
	else    rstate <= rnstate;
end
always @(*) begin 
	case (rstate)
        // RIDLE:		rnstate = axi_write?((i_waddr[31:28]!=i_raddr[31:28])?((wdone && axi_read)?AREAD:RIDLE):(axi_read?AREAD:RIDLE)):(axi_read?AREAD:RIDLE);
        RIDLE:		rnstate = axi_read ? AREAD :RIDLE;
		AREAD:		rnstate = (o_arvalid&&i_arready)?(unbrust?UBREAD_WAIT:READ):AREAD;
		READ: 		rnstate = i_rlast?FIN:READ;
		UBREAD_WAIT:rnstate = (i_rvalid && o_rready && i_rid==4'b0 && i_rresp<2'b10)?((rcnt==rcntm)?FIN:UBREAD):UBREAD_WAIT;
		UBREAD:		rnstate = AREAD;
		FIN:		rnstate = (k==2)?RDONE:FIN;
        RDONE:      rnstate = (rdone&&wdone||wstate==WIDLE)?RIDLE:RDONE;
		default :   rnstate = RIDLE;
	endcase
end
always @(posedge clk) begin 
	if(rst) begin
		araddr      <= 'b0;
		arid        <= 'b0;
		arlen       <= 'b0;
		arvalid     <= 'b0;
		wen 	    <=1'b0;
		cache_wdata <= 'b0;
        rcnt		<=2'b0;
        rcntm       <=2'b0;
        rready      <=1'b0;
        k           <= 2'b0;
	end else begin
		case (rnstate)
			RIDLE:begin
				araddr  <= 'b0;
				arid    <= 'b0;
				arlen   <= 'b0;
				arvalid <= 'b0;
				wen 	<=1'b0;
                rcnt	<=2'b0;
                rcntm   <=2'b0;
                k       <= 2'b0;
			end 
			//ar通道握手
			AREAD:begin
				araddr  <= unbrust?(uncache?i_raddr:{i_raddr[31:4],rcnt,2'b0}):{i_raddr[31:4],4'b0};
				arid    <= 'b0;
				arlen   <= unbrust?8'b0:8'd1;
				arvalid <= 1'b1;
				rready  <= 1'b1;
				arsize	<= unbrust?(uncache? size_t:3'b010):3'b011;
   				arburst <= unbrust?2'b0:2'b01;
   				rcntm   <= unbrust&&uncache?2'b0:2'b11;
			end
			//read data 通道握手
			READ:begin 
				araddr  <= 'b0;
				arid    <= 'b0;
				arlen   <= 'b0;
				arvalid <= 'b0;
				if (i_rvalid&&o_rready) begin
					cache_wdata [63:0] <= i_rdata;
				end
			end
			UBREAD_WAIT:begin
				araddr  <= 'b0;
				arid    <= 'b0;
				arlen   <= 'b0;
				arvalid <= 'b0;
			end
			UBREAD:begin
				cache_wdata <= (rcnt==2'b00)? {cache_wdata[127:32],i_rdata[31:0]}:
							  ((rcnt==2'b01)? {cache_wdata[127:64],i_rdata[31:0],cache_wdata[31:0]}:
							  ((rcnt==2'b10)? {cache_wdata[127:96],i_rdata[31:0],cache_wdata[63:0]}:cache_wdata));
				rcnt		<= rcnt+1;
			end
			
			FIN:begin 
                if (k == 0) begin
                    cache_wdata <= unbrust?(uncache? {cache_wdata[63:0],i_rdata[63:0]}
								                :{i_rdata[31:0],cache_wdata[95:0]})
								                :{i_rdata,cache_wdata[63:0]};
                    k <= 1; 
                end
                else if (k == 1) begin
                    if (wdone||wstate==WIDLE) begin
                        wen         <= 1;
                        k           <= 2;
                    end
                end
			end
			RDONE:begin
				wen			<= 1'b0;
			end
			default : /* default */;
		endcase
	end
end



// (~uncache&&data_dirty&&(~data_hit)&&(i_mem_ren||i_mem_wen)) || ((dev&&uncache) && i_mem_wen&&i_pc_update)
   
reg [127:0]cache_rdata;
wire wunbrust;
`ifdef ysyx_050369_SOC
assign wunbrust = ~i_waddr[31]; 
`else
assign wunbrust = i_waddr[31:28]!=4'h8; 
`endif
always @(posedge clk ) begin
    if(rst) wstate <= WIDLE;
    else    wstate <= wnstate;
end
always @(*) begin
    case (wstate)
        WIDLE 	:wnstate = axi_write?RCACHE:WIDLE;
        RCACHE	:wnstate = (i_awready&& awvalid)?((wcnts==wcnt)?RDATA:WRITE):RCACHE;
        RDATA   :wnstate = WRITE;
        WRITE   :wnstate = (i_wready&& wvalid)?((wunbrust||(wcnt == wcntm))?WRES:WRITE):WRITE;
        WRES 	:wnstate = (i_bvalid&&o_bready && i_bresp<2'b10 &&i_bid==4'b0)?(wunbrust&&(wcnts!=wcntm)?RCACHE:WDONE):WRES;
        WDONE 	:wnstate = (((axi_read?rdone:1'b1)&&wdone)||uncache)?WIDLE:WDONE;
        default: wnstate = WIDLE;
    endcase
end
always @(posedge clk ) begin 
    if(rst) begin
        awvalid    <= 'b0;
        awaddr     <= 'b0;
        awid       <= 'b0;
        awlen      <= 'b0;
        awsize     <= 'b0;
        awburst    <= 'b0;
        wstrb      <= 'b0;
        wcnt       <= 'b0;
        wcntm      <= 'b0;
        wcnts      <= 'b0;
        wvalid     <= 'b0;
        cache_rdata<= 'b0;
    end else begin
        case (wnstate)
            WIDLE:begin 
                awvalid    <= 'b0;
                awaddr     <= 'b0;
                awid       <= 'b0;
                awlen      <= 'b0;
                awsize     <= 'b0;
                awburst    <= 'b0;
                wstrb      <= 'b0;
                wcnt       <= 'b0;
                wcntm      <= 'b0;
                wcnts      <= 'b0;
                wvalid     <= 'b0;
                cache_rdata<= 'b0;
            end
            RCACHE:begin 
                awvalid    <= 1'b1;
                awaddr     <= uncache?i_waddr:(wunbrust?{i_waddr[31:4],wcnt,2'b0}:dirty_addr);
                awid       <= 'b0;
                awlen      <= wunbrust?8'b0:8'b1;
                awsize     <= wunbrust?(uncache?size_t:3'b10):3'b011;
                awburst    <= wunbrust?2'b00:2'b01;
                wcntm      <= wunbrust?(uncache?2'b0:2'b11):2'b1;
            end
            RDATA:begin
                awvalid     <= 'b0;
                cache_rdata <= i_wdata;
            end
            WRITE:begin 
                if (o_wvalid&&i_wready) begin
                    wcnt       <= wcnt + 1;
                    wvalid     <= 'b0;
                end
                else begin 
                    awvalid    <= 'b0;
                    // wstrb      <= uncache?wstrb_t:(unbrust?8'h07:8'hf);
                    wstrb      <= uncache?wstrb_t:(wunbrust?8'hf:8'hff);
                    wvalid     <= 1'b1;
                end
            end
            WRES:begin 
                if (o_wvalid&&i_wready && wunbrust) begin
                    wcnt       <= wcnt + 1;
                    wcnts      <= wcnt;
                    wvalid     <= 'b0;
                end
                bready     <= 1'b1;
                wvalid     <= 'b0;
            end
            WDONE:begin 
            end
            default : /* default */;
        endcase
    end
end
always @(*) begin
    case (wcnt)
        2'b00 : wdata =  wunbrust?{32'b0,cache_rdata[31: 0] }:cache_rdata[63:0];
        2'b01 : wdata =  wunbrust?{32'b0,cache_rdata[63:32] }:cache_rdata[127:64];
        2'b10 : wdata =           {32'b0,cache_rdata[95:64] };
        2'b11 : wdata =           {32'b0,cache_rdata[127:96]};
        default: wdata = 64'b0;
    endcase
end
assign o_wlast          = (wcnt == wcntm)&&o_wvalid&&i_wready;
assign wdone            = wstate == WDONE;
assign rdone            = rstate == RDONE;
assign o_awvalid        = awvalid;
assign o_awaddr         = awaddr;
assign o_awid           = awid;
assign o_awlen          = awlen;
assign o_awsize         = awsize;
assign o_awburst        = awburst ;  
assign o_wvalid         = wvalid;
assign o_wdata          = wdata;
assign o_wstrb          = wstrb;
assign o_bready         = bready ;    
assign o_araddr         =  araddr;
assign o_arid           =  arid;
assign o_arlen          =  arlen;
assign o_arvalid        =  arvalid;
assign o_rready         =  rready;
assign o_arsize         =  arsize;
assign o_arburst        =  arburst ;
endmodule